﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Routing;
using System.Collections.Specialized;

using Microsoft.Practices.Unity;

using ERPStore.Extensions;
using ERPStore.Services;
using ERPStore.Web.Html;
using ERPStore.Web.Extensions;

using CloudSoft.Extensions;

namespace ERPStore.Web.Controllers
{
	public partial class CatalogController
	{
		[ActionFilters.TrackerActionFilter]
		public ActionResult Product(string code, string name)
		{
			if (code.IsNullOrTrimmedEmpty())
			{
				Logger.Warn("Product without code");
				return View("NoProductFound");
			}
			code = code.Trim().TrimEnd('/').Replace("__", "/");
			Logger.Debug("GetProduct : {0}", code);
			var product = CatalogService.GetProductByCode(code);
			if (product == null)
			{
				product = RewriterService.RecoverableProduct(code);
				if (product == null)
				{
					return RewriterService.RewriteUrl(Request);
				}
				ViewBag.Product = product;
				return View("NoProductFound");
			}
			Logger.Debug("Found product : {0}", product.Title);

			// SEO : Only 1 url by product
			if (!product.Link.IsNullOrTrimmedEmpty()
				&& !(name??string.Empty).TrimEnd('/').Equals(product.Link.TrimEnd('/'), StringComparison.InvariantCultureIgnoreCase)
				&& Request["from"] == null)
			{
				var url = Url.Href(product).AddParameter("from", "oldproducturl");
				return RedirectPermanent(url);
			}

			// Recherche des tarifs client si celui-ci est connecté
			OfferService.ApplyOffers(product, User.CurrentUser);
			// For Tracker
			ViewData["productCode"] = code;
			ViewData["productId"] = product.Id;
			ViewData.Model = product;
			if (product.VariationProductParentId.HasValue)
			{
				Logger.Debug("GetVariations");
				var parentVariation = CatalogService.GetVariationProductById(product.VariationProductParentId.Value);
				if (parentVariation != null)
				{
					Logger.Debug("Variations found");
					ViewBag.Variation = parentVariation;
					return View("VariationProduct");
				}
				else
				{
					Logger.Debug("Variations not found");
				}
			}
			else if (product.IsParentVariation)
			{
				Logger.Debug("Get Default Variation");
				var defaultVariation = CatalogService.GetDefaultVariantByProductVariationId(product.Id);
				if (defaultVariation != null)
				{
					Logger.Debug("Default variation loaded");
					ViewData.Model = defaultVariation;
				}
				else
				{
					Logger.Debug("Default variation not found");
				}
			}
			return View();
		}

		[Authorize(Roles = "customer")]
		[ActionFilters.TrackerActionFilter]
		public ActionResult CustomerProduct(string s)
		{
			var filter = CatalogService.CreateProductListFilter(HttpContext.GetWebContextParameterList());
			filter.Search = s;
			if (User.CurrentUser.Corporate != null)
			{
				filter.CorporateId = User.CurrentUser.Corporate.Id;
			}
			else
			{
				filter.UserId = User.CurrentUser.Id;
			}
			var result = GetProductList(filter);

			if (result.IsNullOrEmpty())
			{
				return View("NoProductFound");
			}

			result.ListType = ERPStore.Models.ProductListType.Customer;

			EventPublisherService.PublishAsync(new Events.ProductListEvent(User, result, ERPStore.Models.ProductListType.Customer));

			ViewData.Model = result;
			return View("ProductCustomer");
		}

		[ActionFilters.TrackerActionFilter]
		public JsonResult JsProductInfo(string productCode)
		{
			var product = CatalogService.GetProductByCode(productCode);
			if (product == null)
			{
				return new JsonResult();
			}
			return Json(new
			{
				Title = product.Title,
				Quantity = product.Packaging,
			});
		}

		#region PartialRendering

		/// <summary>
		/// Shows the product list view.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="viewName">Name of the view.</param>
		/// <param name="productCount">The product count.</param>
		/// <param name="sort">The sort.</param>
		/// <returns></returns>
		public ActionResult ShowProductListView(ERPStore.Models.ProductListType type, string viewName, int? productCount, List<ERPStore.Models.SortProperty> sort)
		{
			var key = string.Format("ShowProductListView|{0}|{1}", type, productCount.GetValueOrDefault(int.MaxValue));
			var list = CacheService[key] as IList<ERPStore.Models.Product>;

			if (list == null)
			{
				var filter = CatalogService.CreateProductListFilter(HttpContext.GetWebContextParameterList());
				filter.ListType = type;

				if (sort.IsNotNullOrEmpty())
				{
					foreach (var item in sort)
					{
						filter.SortList.Add(item);
					}
				}
				list = GetProductList(filter, productCount.GetValueOrDefault(-1));
				CacheService.Add(key, list, DateTime.Now.AddHours(1));
			}

			var user = User.CurrentUser;
			// Réapplication des offres car les produits sont en cache
			foreach (var item in list)
			{
				OfferService.ApplyOffers(item, user);
			}

			return PartialView(viewName, list);
		}

		public ActionResult ShowRelationalProductList(string productCode, string viewName)
		{
			// Hack bot sans paramètre
			if (productCode.IsNullOrTrimmedEmpty())
			{
				return Content(string.Empty);
			}

			string key = string.Format("RelationalProductList{0}", productCode);
			var result = CacheService[key] as Dictionary<ERPStore.Models.ProductRelationType, List<ERPStore.Models.Product>>;
			if (result.IsNullOrEmpty())
			{
				result = new Dictionary<ERPStore.Models.ProductRelationType, List<ERPStore.Models.Product>>();
				var p = CatalogService.GetProductByCode(productCode);
				if (p == null)
				{
					return new EmptyResult();
				}
				var list = CatalogService.GetProductRelations(p.Id).Distinct();
				if (list.IsNotNullOrEmpty())
				{
					var productIdList = list.Select(i => i.ChildProductId).Distinct();
					var productList = CatalogService.GetProductListByIdList(productIdList, true);
					SubstituteVariations(productList);

					var complementaryRelations = from product in productList
												 from relation in list
												 where relation.ChildProductId == product.Id
													   && relation.ProductRelationType == ERPStore.Models.ProductRelationType.Complementary
												 select product;

					var similarRelations = from product in productList
										   from relation in list
										   where relation.ChildProductId == product.Id
												 && relation.ProductRelationType == ERPStore.Models.ProductRelationType.Similar
										   select product;

					var substituteRelations = from product in productList
											  from relation in list
											  where relation.ChildProductId == product.Id
													&& relation.ProductRelationType == ERPStore.Models.ProductRelationType.Substitute
											  select product;


					if (complementaryRelations.Count() > 0)
					{
						result.Add(ERPStore.Models.ProductRelationType.Complementary, complementaryRelations.ToList());
					}
					if (substituteRelations.Count() > 0)
					{
						result.Add(ERPStore.Models.ProductRelationType.Substitute, substituteRelations.ToList());
					}
					if (similarRelations.Count() > 0)
					{
						result.Add(ERPStore.Models.ProductRelationType.Similar, similarRelations.ToList());
					}
				}
				CacheService.Add(key, result, DateTime.Now.AddHours(1));
			}


			if (result.IsNullOrEmpty())
			{
				return Content(string.Empty);
			}

			foreach (var item in result)
			{
				foreach (var product in item.Value)
				{
					OfferService.ApplyOffers(product, User.CurrentUser);
				}
			}

			return PartialView(viewName, result);
		}

		public ActionResult ShowContextualProductList(string viewName, List<ERPStore.Models.Product> list)
		{
			var keywords = this.ControllerContext.HttpContext.GetSearchKeywords();

			if (keywords.IsNullOrTrimmedEmpty())
			{
				return new EmptyResult();
			}
			var filter = new ERPStore.Models.ProductListFilter();
			filter.Search = keywords;
			var productList = GetProductList(filter, 10);
			if (productList.IsNullOrEmpty())
			{
				return new EmptyResult();
			}

			// on retire les produits affichés
			if (!list.IsNullOrEmpty())
			{
				foreach (var item in list)
				{
					productList.RemoveAll(i => i.Id == item.Id);
				}
			}

			productList.ListType = ERPStore.Models.ProductListType.Contextual;
			ViewData.Model = productList;
			return PartialView(viewName);
		}

		// For Bot
		public ActionResult ShowCrossProductList()
		{
			return new EmptyResult();
		}

		[AcceptVerbs(HttpVerbs.Post)]
		public ActionResult ShowCrossProductList(string productCode, string viewName)
		{
			var key = string.Format("ProductCrossList:{0}:{1}", productCode, viewName);
			var crossSellingList = CacheService[key] as IList<ERPStore.Models.Product>;
			if (crossSellingList == null)
			{
				var product = CatalogService.GetProductByCode(productCode);

				if (product == null)
				{
					return Content(string.Empty);
				}

				crossSellingList = CatalogService.GetCrossSellingList(product.Id);
				if (crossSellingList == null)
				{
					crossSellingList = new List<ERPStore.Models.Product>();
				}
				CacheService.Add(key, crossSellingList, DateTime.Now.AddHours(1));
			}

			foreach (var product in crossSellingList)
			{
				OfferService.ApplyOffers(product, User.CurrentUser);
			}

			return PartialView(viewName, crossSellingList);
		}

		public ActionResult ShowCrossSellingList(int? productId, string crossSellingViewName, int productCount)
		{
			var crossSellingList = CatalogService.GetCrossSellingList(productId.Value);

			if (crossSellingList != null)
			{
				crossSellingList = crossSellingList.Take(productCount).ToList();
				foreach (var product in crossSellingList)
				{
					OfferService.ApplyOffers(product, User.CurrentUser);
				}
			}
			else
			{
				crossSellingList = new List<ERPStore.Models.Product>();
			}
			return PartialView(crossSellingViewName, crossSellingList);
		}

		// [ActionFilters.PartialRenderActionFilter(Order=1)]
		public ActionResult ShowHeadProductOfCategory(int productCategoryId, string viewName)
		{
			var product = CatalogService.GetHeadProductOfCategory(productCategoryId);
			if (product == null)
			{
				Logger.Warn(string.Format("Product missing in category {0}", productCategoryId));
				return Content(string.Empty);
			}
			OfferService.ApplyOffers(product, User.CurrentUser);

			return PartialView(viewName, product);
		}

		public ActionResult ShowProductVariationListByProduct(string variationParentProductCode, string selectedProductCode, string viewName, string position = null, string from = null, string query = null)
		{
			var product = CatalogService.GetVariationProductByCode(variationParentProductCode);
			if (product == null)
			{
				return new EmptyResult();
			}
			var table = CatalogService.GetProductVariationListByProductId(product.Id);
			ViewData.Model = table;
			ViewBag.SelectedProductCode = selectedProductCode;
			ViewBag.From = from;
			ViewBag.Query = query;
			ViewBag.Position = position;

			return PartialView(viewName);
		}

		public ActionResult ShowVariationListByProduct(string productCode, string viewName)
		{
			var product = CatalogService.GetProductByCode(productCode);
			if (product == null)
			{
				return new EmptyResult();
			}
			var variationList = CatalogService.GetVariationValueListByProductId(product.Id);
			if (variationList.IsNullOrEmpty())
			{
				return new EmptyResult();
			}
			ViewData.Model = variationList;
			return PartialView(viewName);
		}

		// [OutputCache(Duration = 300, VaryByParam = "*")]
		public ActionResult ShowProductStockInfo(string productCode, string viewName)
		{
			if (productCode.IsNullOrTrimmedEmpty()
				|| viewName.IsNullOrTrimmedEmpty())
			{
				return Content(string.Empty, "text/plain");
			}
			var stockInfo = GetProductStockInfoByCode(productCode);
			ViewData.Model = stockInfo;
			return PartialView(viewName);
		}

		// [ActionFilters.PartialRenderActionFilter]
		public ActionResult ShowProductExtendedPropertyList(string viewName)
		{
			ViewData.Model = CatalogService.GetProductPropertyGroupList();
			return PartialView(viewName);
		}

		public ActionResult ShowContextualProductExtendedPropertyList(string viewName)
		{
			var searchFilter = CatalogService.CreateProductListFilter(HttpContext.GetWebContextParameterList());
			ViewData.Model = CatalogService.GetProductExtendedPropertyListBySearch(searchFilter);
			return PartialView(viewName);
		}

		public ActionResult ShowPictureList(ERPStore.Models.Product product, int size, int normalWidth, int normalHeight, string viewName)
		{
			var pictureList = new List<ERPStore.Models.Media>();

			var list = DocumentService.GetMediaList(product);
			if (list.IsNullOrEmpty())
			{
				return Content("<!-- no picture -->");
			}

			var allowedExtensionList = new List<string>()
				{
					".gif"
					,".jpg"
					,".png"
					,".jpeg"
					,".bmp"
				};

			foreach (var item in list)
			{
				var fileName = item.FileName;

				// Logger.Debug("Process attached picture : " + item.SerializeToXml());

				if (item.MimeType == null
					&& !item.ExternalUrl.IsNullOrTrimmedEmpty())
				{
					try
					{
						fileName = DocumentService.GetFileNameFromUrl(item.ExternalUrl);
					}
					catch (Exception ex)
					{
						Logger.Warn(ex.Message);
						continue;
					}

					// On verifie s'il s'agit d'une image
				}
				else if (item.MimeType != null
					&& !item.MimeType.StartsWith("image/"))
				{
					Logger.Debug("Is not picture : {0}", item.MimeType);
					continue;
				}

				string ext = ".png";
				if (!fileName.IsNullOrTrimmedEmpty())
				{
					ext = System.IO.Path.GetExtension(fileName);
				}
				if (!allowedExtensionList.Any(i => i.Equals(ext, StringComparison.InvariantCultureIgnoreCase)))
				{
					Logger.Debug("Is not picture extension : {0}", ext);
					continue;
				}

				var pos = list.IndexOf(item);
				string imagePattern = "/images/{0}/{1}/{2}/{3}-PIC{4:###}{5}";
				item.IconeSrc = string.Format(imagePattern, item.Id, size, size, product.Code, pos, ext);
				item.Url = string.Format(imagePattern, item.Id, normalWidth, normalHeight, product.Code, pos, ext);
				if (product.DefaultImage != null
					&& item.Id == product.DefaultImage.Id)
				{
					item.IsDefault = true;
				}
				pictureList.Add(item);
			}
			ViewData.Model = pictureList;
			return PartialView(viewName);
		}

		[OutputCache(VaryByParam="*", Duration=600, Location=System.Web.UI.OutputCacheLocation.ServerAndClient)]
		public ActionResult ShowProductByCode(string productCode, string viewName, string position = null, string from = null, string query = null)
		{
			if (productCode.IsNullOrEmpty())
			{
				return new EmptyResult();
			}

			var product = CatalogService.GetProductByCode(productCode);
			if (product == null)
			{
				return new EmptyResult();
			}

			OfferService.ApplyOffers(product, User.CurrentUser);

			if (product.VariationProductParentId.HasValue)
			{
				Logger.Debug("GetVariations");
				var parentVariation = CatalogService.GetVariationProductById(product.VariationProductParentId.Value);
				if (parentVariation != null)
				{
					Logger.Debug("Variations found");
					ViewBag.Variation = parentVariation;
				}
			}

			ViewData.Model = product;
			ViewBag.Position = position;
			ViewBag.From = from;
			ViewBag.Query = query;

			return PartialView(viewName);
		}

		#endregion

		private void SubstituteVariations(IList<ERPStore.Models.Product> result)
		{
			// Suppression des vides
			result.RemoveAll(i => i == null);
			// Recherche des variants
			var variantList = result.Where(i => i.VariationProductParentId.HasValue).ToList();
			// Suppression des variants dans la liste initiale
			result.RemoveAll(i => i.VariationProductParentId.HasValue);

			// On vide la liste pour trouver le variant par defaut
			while (true)
			{
				var variant = variantList.FirstOrDefault();
				if (variant == null)
				{
					break;
				}

				if (result.Any(i => i.Code == variant.Code
					|| i.VariationProductParentId == variant.VariationProductParentId))
				{
					variantList.Remove(variant);
					continue;
				}

				var defaultVariant = CatalogService.GetDefaultVariantByProductVariationId(variant.Id);
				defaultVariant = defaultVariant ?? variant;
				variantList.RemoveAll(i => i.VariationProductParentId.Value == variant.VariationProductParentId.Value);

				result.Insert(0, defaultVariant);
			}
		}

	}
}
